package com.uab.ia.utils;

import java.util.ArrayList;

import android.os.AsyncTask;
import android.util.Log;

import com.uab.ia.entidades.Camino;
import com.uab.ia.entidades.Conexion;
import com.uab.ia.entidades.Node;

public class AEstrellaParadas extends AsyncTask<Long, Void, Camino> {

	/*
	 * Aqui declara les variables:
	 * 
	 * private ArrayCaminos openset; private ArrayCaminos closedset; private
	 * Camino current; ....
	 */
	boolean enc;
	private long start;
	private long end;
	private OnAEstrellaParadasListener listener;
	private Utils utils;
	private Camino open;
	private ArrayList<Long> closed;

	@Override
	protected Camino doInBackground(Long... params) {

		start = params[0];
		end = params[1];

		Double acumulado = 0.0;
		Double distance = 0.0;
		int acumuladoParadas = 0;
		boolean auxTrobat=false;

		utils = Utils.getInstance();
		Node mejor = new Node(start);

		open = new Camino();
		closed = new ArrayList<Long>();
		mejor.setCostG(utils.getEstimatedHeuristic(start, end));
		mejor.setCostA(0.0);
		mejor.setParadasA(0);
		mejor.setParadasG(utils.getEstimatedHeuristicParadas(mejor.id, end));
		open.add(mejor);
		mejor = buscarMejor();

		

		if (start == end) {
			Camino c = new Camino();
			c.add(new Node(start));
			c.add(new Node(end));
			c.setnParadas(0);
			return c;
		}

		while (!open.isEmpty()) {
			

			enc = inTheEnd(mejor.id, end);
			boolean buenRollo = false;
			
			Log.i("tag", "ID MEJOR: " + mejor.id+ " END: "+ end);

			if (enc) {
				
				if (!buenRollo) {
					Camino c = new Camino();
					c.add(mejor);
					c.setCosteA(mejor.getCostA());
					c.setCosteH(mejor.getCostG());
					c.setnParadas(mejor.getParadasT());
					c.creado = true;
					return c;
				}
			}

			acumulado = mejor.getCostA();
			acumuladoParadas = mejor.getParadasA();
			auxTrobat = true;
			
			for (long desti = 1; desti <= 39; desti++) {
				if (desti != mejor.id) {
					
					Conexion c = utils.getConexion(mejor.id, desti);
					distance = utils.getDistanceBetweenEstaciones(mejor.id, desti);
					if (c.isConected() || distance==0.0){
						if (!closed.contains(desti)) {
						Node newNode = new Node(desti);
						newNode.setCostA(acumulado
								+ utils.getTimeBetweenEstaciones(mejor.id,
										newNode.id));
						newNode.setCostG(utils.getEstimatedHeuristic(newNode.id,
								end));
						
						newNode.setParadasA(acumuladoParadas+1);
						
						newNode.setParadasG(utils.getEstimatedHeuristicParadas(mejor.id, desti));
						
						
							newNode.setParentId(mejor.id);
							newNode.setParent(mejor);
							open.add(newNode);
						}	
					}
					

				}
			}
			if (closed.size()==38){
				Node nodofinal; 
				nodofinal = buscarID(end);
				Camino c = new Camino();
				c.add(nodofinal);
				c.setCosteA(nodofinal.getCostA());
				c.setCosteH(nodofinal.getCostG());
				c.setnParadas(nodofinal.getParadasT());
				c.creado = true;
				return c;
			}
			if (mejor.id !=end){
				closed.add(mejor.id);
			}
			if(mejor.id!=end){
				open.remove(mejor);	
			}
			mejor = buscarMejor();

		}

		return null;
	}

	private Node buscarID(long id) {
		Double basico = open.get(0).getCosteT();
		int paradas = open.get(0).getParadasT();
		Node nodeReturn=open.get(0);
		for (Node node : open) {
			if (node.id == id) {
				if (node.getParadasT()<paradas){
					basico = node.getCosteT();
					nodeReturn = node;
				}
				if(node.getParadasT()==paradas && node.getCosteT()<basico){
					basico = node.getCosteT();
					nodeReturn = node;
				}
			}
		}
				return nodeReturn;
	}

	private Node buscarMejor() {
		Double basico = open.get(0).getCosteT();
		int paradas = open.get(0).getParadasT();
		Node nodeReturn = open.get(0);
		for (Node node : open) {
			if (node.getParadasT() < paradas && !closed.contains(node.id)) {
				basico = node.getCosteT();
				paradas = node.getParadasT(); 
				nodeReturn = node;	
			}
			if(node.getParadasT() == paradas && node.getCosteT()<basico  && !closed.contains(node.id)){
				basico = node.getCosteT();
				paradas = node.getParadasT(); 
				nodeReturn = node;
			}
		}
		return nodeReturn;
	}

	private boolean inTheEnd(long idNodeMejor, long idEND) {
		if (idNodeMejor == idEND) {
			return true;
		}
		return false;
	}

	@Override
	protected void onPostExecute(Camino camino) {
		super.onPostExecute(camino);
		if (listener != null) {
			if (camino != null) {
				listener.OnCaminoEncontrado(camino, start, end);
			} else {
				listener.OnNoHayCamino(start, end);
			}
		}
	}

	public OnAEstrellaParadasListener getListener() {
		return listener;
	}

	public void setListener(OnAEstrellaParadasListener listener) {
		this.listener = listener;
	}

	public interface OnAEstrellaParadasListener {
		void OnCaminoEncontrado(Camino c, long start, long end);

		void OnNoHayCamino(long start, long end);
	}
}
